package item.pickable;

import attribute.*;
import be.kuleuven.cs.som.annotate.*;

/**
 * @invar A Energy item must at all time have a valid energy.
 * 			|canHaveAsEnergy(getEnergy())
 *
 */
public abstract class EnergyItem extends PickableItem{
	private final static Energy MIN_ENERGY = new Energy(0, EnergyUnit.Wattsecond);
	private Energy energy;
	
	/**
	 * Drains the given amount of energy from the eneryItem's energy.
	 * 
	 * @param energy
	 * 			The energy that has to be drained
	 * 
	 * @pre	The given energy must be a valid energy.
	 * 		|this.canHaveAsEnergy(energy)
	 * 
	 * @pre	The energyItem's energy minus the given energy must be a valid energy.
	 * 		|this.canHaveAsEnergy(this.getEnergy()-energy)
	 * 
	 * @post The energyItem's energy is set as the energyItem's initial energy minus the given energy.
	 * 			|new.getEnergy() = (this.getEnergy().subtract(energy))
	 */
	public void drainEnergy(Energy energy){
		assert(canHaveAsEnergy(energy));
		assert(canHaveAsEnergy(this.getEnergy().subtract(energy)));	
		this.setEnergy(this.getEnergy().subtract(energy));
	}
	
	/**
	 * Checks whether the given initial energy is valid
	 * 
	 * @param initialEnergy
	 * 			The energy that needs to be checked.
	 * @return ...
	 * 			|result == 
	 * 			|	(initialEnergy != null) 
	 * 			|		&& canHaveAsEnergy(initialEnergy.getEnergyDouble(), initialEnergy.getEnergyUnit())
	 */
	public  boolean canHaveAsEnergy(Energy initialEnergy){
		
		return (initialEnergy != null) && canHaveAsEnergy(initialEnergy.getEnergyDouble(), initialEnergy.getEnergyUnit());
	}
	
	public abstract boolean canHaveAsEnergy(double energy, EnergyUnit unit);
	
	
	/**
	 * Returns the energy of this battery.
	 * 
	 * @return ...
	 * 			|this.energy
	 * @throws IllegalStateException
	 * 			...
	 * 			|energy == null
	 */
	@Basic @Raw
	public Energy getEnergy() throws IllegalStateException{
		if(energy == null)
			throw new IllegalStateException();
		return this.energy;
	}
	
	/**
	 * Returns the Min energy for this class and subclasses.
	 */
	public static Energy getMinEnergy(){
		return MIN_ENERGY;
	}
	
	/**
	 * Sets the pickable item's energy to the given energy.
	 * 
	 * @param energy
	 * 			The energy to be set.
	 * 
	 * @pre The given energy must be a valid energy.
	 * 			|this.canHaveAsEnergy(energy)
	 * 
	 * @post The new energy of this pickAble item is the same as the given energy.
	 * 			|new.getEnergy() == energy 
	 * 
	 */
	public void setEnergy(Energy energy){
		assert(this.canHaveAsEnergy(energy));
		if(!this.isTerminated())
			this.energy = energy;
	}

	@Override
	public void hitByLaser(){
		this.setEnergy(this.getEnergy().add(new Energy(500, EnergyUnit.Wattsecond)));
	}
	
	@Override
	public boolean hasAtleast(Object condition){
		if(condition.getClass() == Energy.class){
			if((this.getEnergy().compareTo((Energy)condition)) >= 0)
					return true;
		}
		else if(condition.getClass() == Position.class){
			if((this.getPosition() == ((Position)condition)))
				return true;
		}
		return false;
	}
}
